home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $Source: dh1:network/parnet/Sana2/Sources/spar_funcs.c,v $
- ** $State: Exp $
- ** $Revision: 37.2 $
- ** $Date: 93/12/17 23:12:43 $
- ** $Author: S.A.Pechler $
- **
- ** Amiga SANA-II Example PARnet device driver.
- **
- ** SPAR code.
- **
- ** Based on the Amiga SANA-II Example SLIP device driver code by bj,
- ** which is (C) Copyright 1992 Commodore-Amiga, Inc.
- ** the rhslip.device by Olaf Seibert <rhialto@mbfys.kun.nl>, and on
- ** the agnet.device code by ppessi <Pekka.Pessi@hut.fi>, which is
- ** Copyright (c) 1993 AmiTCP/IP Group,
- ** Helsinki University of Technology, Finland.
- ** All rights reserved.
- **
- */
-
- #include "device_protos.h"
-
- struct IntuitionBase *IntuitionBase=NULL;
-
- extern int atoi(const char *); /* From stdlib.h */
-
- #ifdef DEBUG
-
- #include "spar_debug.h"
-
- struct Window *DebWin1=NULL;
- struct IOStdReq *DebReq=NULL;
- struct MsgPort *DebPort=NULL;
-
-
- # ifdef __STDC__
- # include <stdarg.h>
-
- extern int vsprintf(char *, const char *, va_list); /* from stdio.h */
-
- void LogMessage(char *fmt, ...)
- {
- va_list args;
- # else
- # include <varargs.h>
-
- void LogMessage(va_alist)
- va_dcl
- {
- char *fmt;
- va_list args;
- # endif
-
- char DebugText[128];
-
- #ifdef __STDC__
- va_start(args, fmt);
- #else
- va_start(args);
- fmt = va_arg(args, char *);
- #endif
-
- vsprintf(DebugText,fmt,args);
-
- if(DebReq && DebReq->io_Device)
- {
- DebReq->io_Command=CMD_WRITE;
- DebReq->io_Data=(APTR)DebugText;
- DebReq->io_Length=-1L;
- DoIO((struct IORequest *)DebReq);
- }
-
- va_end(args);
- }
-
-
- void initsyslog(void)
- {
-
- if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37L))
- {
- DebWin1=OpenWindow(&DebugWin);
-
- if(DebPort=CreateMsgPort())
- if(DebReq=CreateIORequest(DebPort,sizeof(struct IOStdReq)))
- {
- DebReq->io_Data=(APTR) DebWin1;
- DebReq->io_Length= sizeof(struct Window);
- OpenDevice("console.device",0, (struct IORequest *)DebReq, 0);
- }
-
- }
- }
-
- void uninitsyslog(void)
- {
-
- AbortIO((struct IORequest *)DebReq);
- WaitIO((struct IORequest *)DebReq);
-
- while(GetMsg(DebPort));
-
- CloseDevice((struct IORequest *)DebReq);
-
- if(DebReq) DeleteIORequest(DebReq);
- if(DebPort) DeleteMsgPort(DebPort);
-
-
- if (DebWin1) CloseWindow(DebWin1);
- if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
- }
- #else /* No debugging, use intuition only for error messages */
-
- void initintuition(void)
- {
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37L);
- }
-
- void uninitintuition(void)
- {
- if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
- }
-
- #endif /* DEBUG */
-
-
- /*
- **
- ** ReadConfig
- **
- ** Attempt to read in and parse the driver's configuration file.
- **
- ** The files are named by ENV:SANA2/sparX.config where X is the decimal
- ** representation of the device's unit number.
- **
- */
-
- BOOL ReadConfig(struct SPARDevUnit *sdu)
- {
- UBYTE *linebuff,conffile[40]; /* temporary linebuffer & filename */
- STRPTR termchar; /* line terminator */
- struct RDArgs *rdargs;
- BPTR ConfigFile; /* DOS file desciptor */
- LONG args[4]; /* arguments to read from the file */
- BOOL status = FALSE;
- ULONG linenum=0; /* line counter in config file */
- UWORD i;
-
- struct EasyStruct es; /* For errormessage to user */
-
- /* initialize structure for a possible error message */
- es.es_StructSize=sizeof(struct EasyStruct);
- es.es_Flags=0;
- es.es_Title=(char *)SPARName;
- es.es_GadgetFormat="Okay";
-
- /* Create the name of our config file.. */
- sprintf(conffile,"ENV:SANA2/spar%ld.config",(ULONG)sdu->sdu_UnitNum);
-
- /* ...and open it. */
- if(ConfigFile = Open(conffile,MODE_OLDFILE))
- {
- /* Here, I use ReadArgs() to do the file parsing for me. */
-
- if(linebuff = AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC))
- {
- if(rdargs = AllocDosObject(DOS_RDARGS, NULL))
- {
- while(FGets(ConfigFile, linebuff, 255))
- {
- linenum++;
-
- if(linebuff[0] == '#') /* Skip comment lines */
- continue;
-
- rdargs->RDA_Source.CS_Buffer = linebuff;
- rdargs->RDA_Source.CS_Length = 256;
- rdargs->RDA_Source.CS_CurChr = 0;
- rdargs->RDA_DAList = NULL; /* MUST be initalized to NULL */
-
- /* ReadArgs() requires that the line be null-terminated
- * or funny things happen. */
-
- termchar = (STRPTR) linebuff + strlen(linebuff);
- *termchar = '\n';
- termchar++;
- *termchar = 0;
-
- for(i = 0; i< 3; i++) args[i]=0; /* clear argument list */
-
- /* Parse the line...*/
-
- /* I use 'DESTADDR' as a string, otherwise I can't check if
- * it's omitted. (when using 'DESTADDR/N' and you don't
- * fill in this argument in the config.file, args[3] will
- * still point to something.)
- */
- if(ReadArgs("PARNAME/A,PARUNIT/A/N,PARADDR/A/N,DESTADDR",args,rdargs))
-
- /* if(ReadArgs("PARNAME/A,PARUNIT/A/N,PARADDR/A/N,DESTADDR/N",args,rdargs))
- */
- {
- strcpy(sdu->sdu_ParDevName,(STRPTR)args[0]);
- sdu->sdu_ParUnitNum = *((ULONG *)args[1]);
- sdu->sdu_StAddr = sdu->sdu_HwAddr = (UBYTE) *((ULONG *)args[2]);
-
- if(args[3]) sdu->sdu_DestAddr = (UBYTE) atoi((char *)args[3]);
-
- /* if(args[3]) sdu->sdu_DestAddr = (UBYTE) *((ULONG *)args[3]);
- */
- else sdu->sdu_DestAddr = (UBYTE) 0;
-
- /* check hardware addresses */
- if ((sdu->sdu_HwAddr!=0) && (sdu->sdu_HwAddr!=255) &&
- (sdu->sdu_DestAddr!=255))
- status = TRUE;
- else
- {
- /* send a notification to the user */
- es.es_TextFormat="Invalid hardware address (%d) given.";
- EasyRequestArgs(NULL, &es, 0, &sdu->sdu_HwAddr);
- }
- debug(("Config: Hardware addr:%d, dest.addr:%d\n",(int)sdu->sdu_HwAddr,(int)sdu->sdu_DestAddr))
-
- FreeArgs(rdargs);
- break;
- }
- else /* Argument error */
- {
- /* Produce an error message in a requester */
- es.es_TextFormat="Error in configuration file on line %ld.";
- EasyRequestArgs(NULL, &es, 0, &linenum);
- break;
- }
- }
- FreeDosObject(DOS_RDARGS,rdargs);
- }
- FreeMem(linebuff, 256);
- }
- Close(ConfigFile);
- }
- return(status);
- }
-
-
- VOID SendPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct IOParReq *iopar;
- struct BufferManagement *bm;
- struct Spar_Hdr *PktHdr; /* Spar frame header */
-
- bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
-
- /* Check first if destination hardware address is valid */
- if ((ios2->ios2_DstAddr[0]==0) || (ios2->ios2_DstAddr[0]==255))
- {
- PacketDropped(sdu); /* Can't handle addresses 0 and 255 */
-
- debug(("SendPacket: Bad destination addr:%08lx%04lx (packet dropped).\n",*(LONG *)ios2->ios2_DstAddr,*(UWORD *)(ios2->ios2_DstAddr+4)))
- }
-
- else
- {
- /* Copy the data out of the packet into our temporary buffer. */
- if((*bm->bm_CopyFromBuffer)(sdu->sdu_TxBuff+SHDR_LEN,ios2->ios2_Data,ios2->ios2_DataLength))
- {
- PktHdr=(struct Spar_Hdr *)sdu->sdu_TxBuff; /* Pointer to frame header */
-
- /* Create frame header (Ethernet-like) */
-
- PktHdr->SDstAddr=ios2->ios2_DstAddr[0]; /* Place packet destination Spar address */
-
- /* Place my source address in packet header */
- if ((ios2->ios2_SrcAddr[0]==0) || (ios2->ios2_SrcAddr[0]==255)) /* Valid source address ? */
- PktHdr->SSrcAddr=sdu->sdu_StAddr; /* Use internal h/w addr. */
- else
- PktHdr->SSrcAddr=ios2->ios2_SrcAddr[0];
-
- PktHdr->SFrmType=(UWORD)ios2->ios2_PacketType; /* Place frame type */
-
- /* Update statistics, (without header information) */
- PacketSent(sdu,ios2->ios2_DataLength);
-
- /* Destination address ok, send it */
- iopar = sdu->sdu_ParTx;
- iopar->io_Data = sdu->sdu_TxBuff;
- iopar->io_Length = ios2->ios2_DataLength+SHDR_LEN; /* include packet header */
- iopar->io_Data2 = 0L; /* must be 0 if you do not */
- iopar->io_Length2 = 0L; /* use these fields. */
- iopar->io_Command = CMD_WRITE;
- iopar->io_Error = 0; /* is this needed?? */
- iopar->io_Message.mn_Node.ln_Type = 0;
- iopar->io_Port = SPAR_PORT;
- iopar->io_Addr = (UWORD)ios2->ios2_DstAddr[0];
- iopar->io_Flags = PRO_DGRAM;
- /* Send the packet to the PARnet device driver */
- SendIO((struct IORequest *)iopar);
-
- debug(("SendPacket: Sent packet size %ld addr: %08lx%04lx.\n", ios2->ios2_DataLength, *(LONG *)ios2->ios2_DstAddr,*(UWORD *)(ios2->ios2_DstAddr+4)))
- }
- else
- {
- /* Something went wrong...*/
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(sdu,S2EVENT_BUFF);
- }
- }
- TermIO(ios2);
- }
-
-
- /*
- ** This routine is called whenever we think we've got
- ** a complete packet to satisfy a CMD_READ request.
- */
- VOID GotPacket(struct SPARDevUnit *sdu, ULONG length)
- {
- struct IOSana2Req *ios2;
- struct BufferManagement *bm;
- ULONG Offset;
- struct Spar_Hdr *PktHdr; /* Spar frame header */
-
- if(length)
- {
- PacketReceived(sdu,length); /* Update statistics */
-
- PktHdr=(struct Spar_Hdr *)sdu->sdu_RxBuff; /* Pointer to frame header */
-
- /* Find an appropriate request wanting this packet type.
- * Routine gotten from the agnet.device by ppessi <Pekka.Pessi@hut.fi>
- */
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- /* For each queued read request... */
- for (ios2 = (struct IOSana2Req *)sdu->sdu_Rx.mlh_Head;
- ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
- ios2 = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
- {
- /* Does requested packet type match? */
- if (ios2->ios2_PacketType == (ULONG)PktHdr->SFrmType)
- {
- Remove((struct Node *)ios2); /* Yes, get & remove it from list */
- break; /* No more searches needed */
- }
- }
-
- if(!ios2) /* Nobody wants this packet type? So, it's orphan */
- {
- ReceivedOrphan(sdu); /* Update statistics */
- if (!(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_RxOrph)))
- PacketDropped(sdu); /* Nobody is interested in this packet, drop it */
- }
-
- ReleaseSemaphore(&sdu->sdu_ListLock);
-
- bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
-
- /* Don't strip frame header when RAW data is requested */
- if (ios2->ios2_Req.io_Flags==SANA2IOB_RAW) Offset=0;
- else Offset=SHDR_LEN;
-
- /* Copy the data into the protocol stack's buffer using its
- * supplied callback routine. */
- if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,sdu->sdu_RxBuff+Offset,length-Offset))
- {
- debug(("GotPack (%d): %08lx%08lx%08lx%08lx\n",length-Offset,*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12)))
-
- /* Copy source and destination addresses */
- memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES); /* first clear */
- memset(ios2->ios2_SrcAddr, 0, SANA2_MAX_ADDR_BYTES); /* them both. */
- ios2->ios2_DstAddr[0]=PktHdr->SDstAddr;
- ios2->ios2_SrcAddr[0]=PktHdr->SSrcAddr;
-
- /* Our packetlength (if not SANA2IOB_RAW then strip frame header) */
- ios2->ios2_DataLength = length-Offset;
-
- /* Our packet type */
- ios2->ios2_PacketType = (ULONG)PktHdr->SFrmType;
- #ifdef DEBUG
- debug(("GotPacket: Length:%lx ", ios2->ios2_DataLength))
- if (ios2->ios2_PacketType==ETHERTYPE_ARP) debug(("Type:ARP "))
- else if(ios2->ios2_PacketType==ETHERTYPE_IP) debug(("Type:IP "))
- else debug(("Type:%08lx ",ios2->ios2_PacketType))
- debug(("Source:%08lx%04lx.\n", *(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4) ))
- #endif
- }
- else
- {
- ios2->ios2_DataLength = 0;
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(sdu,S2EVENT_BUFF);
- }
- TermIO(ios2);
- } /* Length */
- }
-
-
- /*
- ** This routine initializes our IO requests and buffers for PARnet i/o .
- */
- BOOL InitPARnet(struct SPARDevUnit *sdu)
- {
- ULONG *clr;
- BOOL status = FALSE;
-
- /* This is a dirty way of clearing some pointers in the struct SPARDevUnit */
- for(clr = (ULONG *) &sdu->sdu_ParRx; clr <= (ULONG *) &sdu->sdu_TxBuff; clr++)
- *clr = 0L;
-
- if(sdu->sdu_TxPort = CreateMsgPort()) /* PARnet CMD_WRITE IORequest reply port */
- if(sdu->sdu_ParTx = CreateIORequest(sdu->sdu_TxPort,sizeof(struct IOParReq)))
- if(sdu->sdu_RxPort = CreateMsgPort()) /* PARnet CMD_READ IORequest reply port */
- if(sdu->sdu_ParRx = CreateIORequest(sdu->sdu_RxPort,sizeof(struct IOParReq)))
- /* Allocate some buffer memory */
- if(sdu->sdu_TxBuff = AllocMem(SPAR_MTU * 2,MEMF_CLEAR|MEMF_PUBLIC))
- {
- sdu->sdu_RxBuff = sdu->sdu_TxBuff + SPAR_MTU;
- status = TRUE; /* flag: initialisation was successful */
- }
-
- if(!status)
- DeinitPARnet(sdu); /* Something went wrong, release all */
- return(status);
- }
-
- /*
- ** This routine cleans up our PARnet i/o requests
- ** and misc. buffers.
- */
- VOID DeinitPARnet(struct SPARDevUnit *sdu)
- {
- if(sdu->sdu_ParTx)
- DeleteIORequest(sdu->sdu_ParTx);
-
- if(sdu->sdu_TxPort)
- DeleteMsgPort(sdu->sdu_TxPort);
-
- if(sdu->sdu_ParRx)
- DeleteIORequest(sdu->sdu_ParRx);
-
- if(sdu->sdu_RxPort)
- DeleteMsgPort(sdu->sdu_RxPort);
-
- if(sdu->sdu_TxBuff)
- FreeMem(sdu->sdu_TxBuff,(SPAR_MTU * 2)); /* release both TxBuff & RxBuff */
-
- }
-
-
- /*
- ** This routine opens the PARnet device driver and attempts to bring
- ** the device online.
- */
- BOOL OpenPARnet(struct SPARDevUnit *sdu)
- {
- BOOL status = FALSE;
- ULONG odflags = 0;
- struct IOParReq *ioTpar,*ioRpar; /* IORequest structures */
-
- /* next variables are used for displaying the error message */
- struct EasyStruct es;
- ULONG args[2];
-
- ioRpar = sdu->sdu_ParRx;
- ioTpar = sdu->sdu_ParTx;
- ioRpar->io_Device = NULL;
-
- if (sdu->sdu_TxPort) /* Is this needed?? */
- {
- ioTpar->io_Message.mn_ReplyPort=sdu->sdu_TxPort;
- ioTpar->io_Port = 0;
- ioTpar->io_Flags = PRO_CONTROL;
-
- if(!OpenDevice(sdu->sdu_ParDevName,sdu->sdu_ParUnitNum,(struct IORequest *)ioTpar,odflags))
- {
- /* Set up our PARnet RX parameters */
- ioRpar->io_Device = ioTpar->io_Device;
- ioRpar->io_Unit = ioTpar->io_Unit;
-
- /* set up IO request for hardware address setting */
- ioTpar->io_Command = PPD_SETADDR;
- ioTpar->io_Addr = (UWORD)sdu->sdu_StAddr;
-
- if(!DoIO((struct IORequest *)ioTpar)) /* Set my hardware address */
- {
- /* Close the device again to reset the PRO_CONTROL mode */
- CloseDevice((struct IORequest *)ioTpar);
-
- /* Open the device in Data Gram mode */
- ioTpar->io_Port = SPAR_PORT;
- ioTpar->io_Flags = PRO_DGRAM;
- if(!OpenDevice(sdu->sdu_ParDevName,sdu->sdu_ParUnitNum,(struct IORequest *)ioTpar,odflags))
- {
- /* Assume we're now online */
- sdu->sdu_State |= SPARUF_ONLINE;
-
- /* check first if the reply port has already been initalized */
- if (sdu->sdu_RxPort) /* Is this really needed?? */
- {
- /* Queue up the initial CMD_READ command for the PARnet driver. */
- ioRpar->io_Message.mn_ReplyPort=sdu->sdu_RxPort;
- ioRpar->io_Port = SPAR_PORT; /* PARnet port to listen on */
- ioRpar->io_Flags = PRO_DGRAM; /* only DataGram mode supported */
- ioRpar->io_Command = CMD_READ;
- ioRpar->io_Length = SPAR_MTU;
- if (sdu->sdu_RxBuff) /* Is this needed?? */
- {
- ioRpar->io_Data = sdu->sdu_RxBuff;
- SendIO((struct IORequest *)ioRpar);
- status = TRUE; /* All ok! */
- }
- }
- }
- if(!status)
- CloseDevice((struct IORequest *)ioTpar);
- }
- else /* Can't set PARnet hardware address */
- CloseDevice((struct IORequest *)ioTpar);
- }
- else /* Can't open device */
- {
- args[0]=(ULONG)sdu->sdu_ParDevName;
- args[1]=(ULONG)sdu->sdu_ParUnitNum;
-
- es.es_StructSize=sizeof(struct EasyStruct);
- es.es_Flags=0;
- es.es_Title="spar.device";
- es.es_TextFormat="Couldn't open %s unit %ld.";
- es.es_GadgetFormat="Okay";
- EasyRequestArgs(NULL, &es, 0, (APTR)args);
- }
- if(sdu->sdu_State & SPARUF_ONLINE)
- MarkTimeOnline(sdu);
- }
- return(status);
- }
-
- /*
- ** This routine aborts any pending activity with the PARnet
- ** device driver and then brings the spar driver offline.
- */
- VOID ClosePARnet(struct SPARDevUnit *sdu)
- {
- AbortIO((struct IORequest *)sdu->sdu_ParRx);
- WaitIO((struct IORequest *)sdu->sdu_ParRx);
-
- while(GetMsg(sdu->sdu_RxPort));
-
- AbortIO((struct IORequest *)sdu->sdu_ParTx);
- WaitIO((struct IORequest *)sdu->sdu_ParTx);
-
- while(GetMsg(sdu->sdu_TxPort));
-
- CloseDevice((struct IORequest *)sdu->sdu_ParRx);
-
- sdu->sdu_State &= ~SPARUF_ONLINE;
-
- }
-
- /*
- ** This routine is called whenever we need to
- ** get more data from the PARnet port.
- */
- VOID QueueParRequest(struct SPARDevUnit *sdu)
- {
- sdu->sdu_ParRx->io_Command = CMD_READ;
- sdu->sdu_ParRx->io_Data = sdu->sdu_RxBuff;
- sdu->sdu_ParRx->io_Length = SPAR_MTU;
-
- SendIO((struct IORequest *)sdu->sdu_ParRx);
- }
-